﻿using System;
using GeoAPI.Geometries;

namespace NetTopologySuite.Geometries.Implementation
{
	public class PackedDoubleCoordinateSequence : PackedCoordinateSequence
	{
		public PackedDoubleCoordinateSequence(double[] coords, int dimensions)
		{
			if (dimensions < 2)
			{
				throw new ArgumentException("Must have at least 2 dimensions");
			}
			if (coords.Length % dimensions != 0)
			{
				throw new ArgumentException("Packed array does not contain an integral number of coordinates");
			}
			base.Dimension = dimensions;
			this._coords = coords;
		}

		public PackedDoubleCoordinateSequence(float[] coordinates, int dimensions)
		{
			this._coords = new double[coordinates.Length];
			base.Dimension = dimensions;
			for (int i = 0; i < coordinates.Length; i++)
			{
				this._coords[i] = (double)coordinates[i];
			}
		}

		public PackedDoubleCoordinateSequence(Coordinate[] coordinates, int dimension)
		{
			if (coordinates == null)
			{
				coordinates = new Coordinate[0];
			}
			base.Dimension = dimension;
			this._coords = new double[coordinates.Length * base.Dimension];
			for (int i = 0; i < coordinates.Length; i++)
			{
				this._coords[i * base.Dimension] = coordinates[i].X;
				if (base.Dimension >= 2)
				{
					this._coords[i * base.Dimension + 1] = coordinates[i].Y;
				}
				if (base.Dimension >= 3)
				{
					this._coords[i * base.Dimension + 2] = coordinates[i].Z;
				}
			}
		}

		public PackedDoubleCoordinateSequence(Coordinate[] coordinates) : this(coordinates, 3)
		{
		}

		public PackedDoubleCoordinateSequence(int size, int dimension)
		{
			base.Dimension = dimension;
			this._coords = new double[size * base.Dimension];
		}

		protected override Coordinate GetCoordinateInternal(int index)
		{
			double x = this._coords[index * base.Dimension];
			double y = this._coords[index * base.Dimension + 1];
			double z = (base.Dimension == 2) ? double.NaN : this._coords[index * base.Dimension + 2];
			return new Coordinate(x, y, z);
		}

		public double[] GetRawCoordinates()
		{
			return this._coords;
		}

		public override int Count
		{
			get
			{
				return this._coords.Length / base.Dimension;
			}
		}

		public override object Clone()
		{
			double[] array = new double[this._coords.Length];
			Array.Copy(this._coords, array, this._coords.Length);
			return new PackedDoubleCoordinateSequence(array, base.Dimension);
		}

		public override double GetOrdinate(int index, Ordinate ordinate)
		{
			return this._coords[(int)(index * base.Dimension + ordinate)];
		}

		public override void SetOrdinate(int index, Ordinate ordinate, double value)
		{
			this.CoordRef = null;
			this._coords[(int)(index * base.Dimension + ordinate)] = value;
		}

		public override Envelope ExpandEnvelope(Envelope env)
		{
			int dimension = base.Dimension;
			for (int i = 0; i < this._coords.Length; i += dimension)
			{
				env.ExpandToInclude(this._coords[i], this._coords[i + 1]);
			}
			return env;
		}

		public override ICoordinateSequence Reversed()
		{
			int dimension = base.Dimension;
			double[] array = new double[this._coords.Length];
			int num = this.Count;
			for (int i = 0; i < this.Count; i++)
			{
				Buffer.BlockCopy(this._coords, i * dimension * 8, array, --num * dimension * 8, dimension * 8);
			}
			return new PackedDoubleCoordinateSequence(array, dimension);
		}

		private readonly double[] _coords;
	}
}
